package com.guinea.core.web;

import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Date;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.beanutils.ConvertUtils;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.action.ActionMessages;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.util.ReflectionUtils;

import com.guinea.core.Constants;
import com.guinea.core.orm.BaseEntity;
import com.guinea.core.orm.HibernateDao;
import com.guinea.core.service.EntityService;
import com.guinea.core.utils.BeanUtils;
import com.guinea.core.utils.CommonUtils;

public abstract class StrutsSimpleAction extends StrutsAction implements
		InitializingBean {

	public static final String REQUEST_PAGE = "page";

	public static final String REQUEST_ENTITY = "entity";

	public static final String FILTER_PREFIX = "filter";

	public static final String FILTER_MAP = "filters";

	protected Class idClass; // Action所管理的Entity的主键类型.

	protected String idName; // Action所管理的Entity的主键名.

	protected String[] methodNames;

	protected Serializable id;

	protected Object entity;

	protected ActionMessages formErrors;

	protected boolean isCreateOperation;

	protected boolean valid;

	public abstract EntityService getEntityService();

	/**
	 * 取得entityClass的函数.
	 */
	protected Class getEntityClass() {
		return getEntityService().getEntityDao().getEntityClass();
	}

	/**
	 * Init回调函数,初始化一系列参数.
	 */
	public void afterPropertiesSet() {
		EntityService entityService = getEntityService();
		HibernateDao entityDao = entityService.getEntityDao();
		// 反射获得entity的主键类型
		try {
			idName = entityDao.getIdName();
			idClass = BeanUtils.getPropertyType(getEntityClass(), idName);
		} catch (Exception e) {
			ReflectionUtils.handleReflectionException(e);
		}
		Method[] ms = getClass().getMethods();
		methodNames = new String[ms.length];
		for (int i = 0; i < ms.length; i++) {
			methodNames[i] = ms[i].getName();
		}
	}

	protected void initProperties() {
		id = null;
		entity = null;
		formErrors = null;
		isCreateOperation = true;
		valid = true;
	}

	private Method findMethod(String name) throws NoSuchMethodException {
		Method m = null;
		for (int i = 0; i < methodNames.length; i++) {
			if (methodNames[i].equals(name)) {
				m = getMethod(name);
				break;
			}
		}
		return m;
	}

	/**
	 * Process the specified HTTP request, and create the corresponding HTTP
	 * response (or forward to another web component that will create it).
	 * Return an <code>ActionForward</code> instance describing where and how
	 * control should be forwarded, or <code>null</code> if the response has
	 * already been completed.
	 * 
	 * @param mapping
	 *            The ActionMapping used to select this instance
	 * @param form
	 *            The optional ActionForm bean for this request (if any)
	 * @param request
	 *            The HTTP request we are processing
	 * @param response
	 *            The HTTP response we are creating
	 * 
	 * @exception Exception
	 *                if an exception occurs
	 */
	public ActionForward execute(ActionMapping mapping, ActionForm form,
			HttpServletRequest request, HttpServletResponse response)
			throws Exception {
		if (isCancelled(request)) {
			ActionForward af = cancelled(mapping, form, request, response);
			if (af != null) {
				return af;
			}
		}

		// Get the parameter. This could be overridden in subclasses.
		String parameter = getParameter(mapping, form, request, response);

		// Get the method's name. This could be overridden in subclasses.
		String name = getMethodName(mapping, form, request, response, parameter);

		// Prevent recursive calls
		if ("execute".equals(name) || "perform".equals(name)) {
			String message = messages.getMessage("dispatch.recursive", mapping
					.getPath());

			log.error(message);
			throw new ServletException(message);
		}

		// Invoke the named method, and return the result
		initProperties();
		ActionForward result = validateMyMethod(mapping, form, request,
				response, name + "Validator");
		if (!valid)
			return result;

		return dispatchMethod(mapping, form, request, response, name);
	}

	/**
	 * Dispatch to the specified method.
	 * 
	 * @since Struts 1.1
	 */
	protected ActionForward validateMyMethod(ActionMapping mapping,
			ActionForm form, HttpServletRequest request,
			HttpServletResponse response, String name) throws Exception {

		// Make sure we have a valid method name to call.
		// This may be null if the user hacks the query string.
		if (name == null || methodNames == null) {
			return null;
		}
		// Identify the method object to be dispatched to
		Method method = null;
		try {
			method = findMethod(name);
		} catch (NoSuchMethodException e) {
			String message = messages.getMessage("validateMyMethod.method",
					mapping.getPath(), name);
			log.error(message, e);

			String userMsg = messages.getMessage(
					"validateMyMethod.method.user", mapping.getPath());
			throw new NoSuchMethodException(userMsg);
		}
		if (method == null)
			return null;

		ActionForward forward = null;
		try {
			Object args[] = { mapping, form, request, response };
			forward = (ActionForward) method.invoke(this, args);

		} catch (ClassCastException e) {
			String message = messages.getMessage("validateMyMethod.return",
					mapping.getPath(), name);
			log.error(message, e);
			throw e;

		} catch (IllegalAccessException e) {
			String message = messages.getMessage("validateMyMethod.error",
					mapping.getPath(), name);
			log.error(message, e);
			throw e;

		} catch (InvocationTargetException e) {
			// Rethrow the target exception if possible so that the
			// exception handling machinery can deal with it
			Throwable t = e.getTargetException();
			if (t instanceof Exception) {
				throw ((Exception) t);
			} else {
				String message = messages.getMessage("validateMyMethod.error",
						mapping.getPath(), name);
				log.error(message, e);
				throw new ServletException(t);
			}
		}

		// Return the returned ActionForward instance
		return (forward);
	}

	/**
	 * 为保存操作添加创建人更新人等信息，保存操作专用
	 * 
	 * @param isNewEntity
	 *            是否创建新对象
	 * @param object
	 * @return
	 */
	protected BaseEntity addSaveData(Object object, boolean isNewEntity) {
		// 保存创建人更新人
		BaseEntity baseEntity = (BaseEntity) object;
		Long userId = CommonUtils.getCurrentUserId();
		if (userId == null)
			// 超级管理员用户
			userId = new Long(0);
		// 新增
		if (isNewEntity) {
			baseEntity.setStatus(Constants.STATUS_VALID);
			baseEntity.setCreatedUser(userId);
			baseEntity.setCreatedDate(new Date());
		} else {// 修改
			baseEntity.setStatus(Constants.STATUS_VALID);
			baseEntity.setUpdatedUser(userId);
			baseEntity.setUpdatedDate(new Date());
		}
		return baseEntity;
	}

	protected Serializable getEntityId(HttpServletRequest request,
			String idName, Class idClass) {
		Serializable id = null;
		String idString = request.getParameter(idName);
		try {
			id = (Serializable) ConvertUtils.convert(idString, idClass);
		} catch (NumberFormatException e) {
			throw new IllegalArgumentException("Wrong when get id from request");
		}
		return id;
	}

	/**
	 * 验证TOKEN
	 * 
	 * @param request
	 * @return
	 */
	protected boolean validateToken(HttpServletRequest request) {
		if (!isTokenValid(request)) {
			return valid = false;
		}
		resetToken(request);
		return true;
	}

	protected boolean validateForm(ActionMapping mapping, ActionForm form,
			HttpServletRequest request) {
		formErrors = form.validate(mapping, request);
		if (formErrors != null && !formErrors.isEmpty())
			return valid = false;
		return true;
	}

	/**
	 * 新建业务对象的函数.
	 */
	protected Object doNewEntity() {
		Object object = null;
		try {
			object = getEntityClass().newInstance();
		} catch (Exception e) {
			log.error("Can't new Instance of entity.", e);
		}
		return object;
	}

	/**
	 * 初始化业务对象的函数.
	 */
	protected void findEntity(ActionForm form, HttpServletRequest request) {
		id = getEntityId(request, idName, idClass);
		if (id != null) {
			entity = getEntityService().get(id);
		}
	}

	protected void initFirst(ActionForm form, HttpServletRequest request) {
		findEntity(form, request);
		// 不是由ID参数得到的entity
//		if (id == null && entity != null) {
//			BaseEntity baseEntity = (BaseEntity) entity;
//			BaseForm baseForm = (BaseForm) form;
//			baseForm.setId(baseEntity.getId());
//			id = baseEntity.getId();
//		}
		if (entity != null) {
			isCreateOperation = false;
			BaseEntity baseEntity = (BaseEntity) entity;
			if(form != null){
				BaseForm baseForm = (BaseForm) form;
				baseForm.setId(baseEntity.getId());
				form = baseForm;
			}
			id = baseEntity.getId();
		} else {
			id = null;
		}
	}

	protected boolean validateEntity() {
		if (entity == null) {
			return valid = false;
		}
		return true;
	}

	/**
	 * 初始化业务对象的函数.
	 */
	protected void doInitEntity(HttpServletRequest request, ActionForm form) {
		if (isCreateOperation) {
			entity = doNewEntity();
		}
		bindEntity(form, entity);
	}

	/**
	 * 保存业务对象的函数.
	 */
	protected void doSaveEntity(HttpServletRequest request, ActionForm form) {
		if (isCreateOperation)
			id = getEntityService().save(entity);
		else {
			getEntityService().update(entity);
		}
	}

	/**
	 * 标记删除业务对象的函数.
	 */
	protected void doEraseEntity(HttpServletRequest request) {
		getEntityService().erase(entity);
	}

}
